home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gdevpx.c < prev    next >
C/C++ Source or Header  |  1997-06-20  |  45KB  |  1,567 lines

  1. /* Copyright (C) 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpx.c */
  20. /* H-P PCL XL driver */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gserrors.h"
  26. #include "gsccolor.h"
  27. #include "gsdcolor.h"
  28. #include "gxcspace.h"        /* for color mapping for images */
  29. #include "gxdevice.h"
  30. #include "gxpath.h"
  31. #include "gdevvec.h"
  32. #include "strimpl.h"
  33. #include "srlx.h"
  34. #include "gdevpxat.h"
  35. #include "gdevpxen.h"
  36. #include "gdevpxop.h"
  37.  
  38. /* ---------------- Device definition ---------------- */
  39.  
  40. /* Define the default resolution. */
  41. #ifndef X_DPI
  42. #  define X_DPI 600
  43. #endif
  44. #ifndef Y_DPI
  45. #  define Y_DPI 600
  46. #endif
  47.  
  48. /* Structure definition */
  49. #define num_points 100        /* must be >= 3 and <= 255 */
  50. typedef enum {
  51.   points_none,
  52.   points_lines,
  53.   points_curves
  54. } point_type_t;
  55. typedef struct gx_device_pclxl_s {
  56.   gx_device_vector_common;
  57.     /* Additional state information */
  58.   pxeMediaSize_t media_size;
  59.   gx_path_type_t fill_rule;    /* ...winding_number or ...even_odd  */
  60.   gx_path_type_t clip_rule;    /* ditto */
  61.   pxeColorSpace_t color_space;
  62.   struct pal_ {
  63.     int size;            /* # of bytes */
  64.     byte data[256 * 3];        /* up to 8-bit samples */
  65.   } palette;
  66.   struct pts_ {            /* buffer for accumulating path points */
  67.     gs_int_point current;    /* current point as of start of data */
  68.     point_type_t type;
  69.     int count;
  70.     gs_int_point data[num_points];
  71.   } points;
  72.   struct ch_ {            /* cache for downloaded characters */
  73. #define max_cached_chars 400
  74. #define max_char_data 500000
  75. #define max_char_size 5000
  76. #define char_hash_factor 247
  77.     ushort table[max_cached_chars * 3 / 2];
  78.     struct cd_ {
  79.       gs_id id;            /* key */
  80.       uint size;
  81.     } data[max_cached_chars];
  82.     int next_in;        /* next data element to fill in */
  83.     int next_out;        /* next data element to discard */
  84.     int count;            /* of occupied data elements */
  85.     ulong used;
  86.   } chars;
  87.   bool font_set;
  88. } gx_device_pclxl;
  89. gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
  90.   "gx_device_pclxl", device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
  91.   gx_device_finalize, st_device_vector);
  92.  
  93. #define pclxl_device_body(dname, depth)\
  94.   std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
  95.                DEFAULT_WIDTH_10THS * X_DPI / 10,\
  96.                DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
  97.                X_DPI, Y_DPI,\
  98.                (depth > 8 ? 3 : 1), depth,\
  99.                (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
  100.                (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
  101.  
  102. /* Driver procedures */
  103. private dev_proc_open_device(pclxl_open_device);
  104. private dev_proc_output_page(pclxl_output_page);
  105. private dev_proc_close_device(pclxl_close_device);
  106. private dev_proc_copy_mono(pclxl_copy_mono);
  107. private dev_proc_copy_color(pclxl_copy_color);
  108. private dev_proc_fill_mask(pclxl_fill_mask);
  109. /*private dev_proc_draw_thin_line(pclxl_draw_thin_line);*/
  110. private dev_proc_begin_image(pclxl_begin_image);
  111. private dev_proc_image_data(pclxl_image_data);
  112. private dev_proc_end_image(pclxl_end_image);
  113. private dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
  114. #define pclxl_device_procs(map_rgb_color, map_color_rgb)\
  115.     {    pclxl_open_device,\
  116.         NULL,            /* get_initial_matrix */\
  117.         NULL,            /* sync_output */\
  118.         pclxl_output_page,\
  119.         pclxl_close_device,\
  120.         map_rgb_color,        /* differs */\
  121.         map_color_rgb,        /* differs */\
  122.         gdev_vector_fill_rectangle,\
  123.         NULL,            /* tile_rectangle */\
  124.         pclxl_copy_mono,\
  125.         pclxl_copy_color,\
  126.         NULL,            /* draw_line */\
  127.         NULL,            /* get_bits */\
  128.         gdev_vector_get_params,\
  129.         gdev_vector_put_params,\
  130.         NULL,            /* map_cmyk_color */\
  131.         NULL,            /* get_xfont_procs */\
  132.         NULL,            /* get_xfont_device */\
  133.         NULL,            /* map_rgb_alpha_color */\
  134.         gx_page_device_get_page_device,\
  135.         NULL,            /* get_alpha_bits */\
  136.         NULL,            /* copy_alpha */\
  137.         NULL,            /* get_band */\
  138.         NULL,            /* copy_rop */\
  139.         gdev_vector_fill_path,\
  140.         gdev_vector_stroke_path,\
  141.         pclxl_fill_mask,\
  142.         gdev_vector_fill_trapezoid,\
  143.         gdev_vector_fill_parallelogram,\
  144.         gdev_vector_fill_triangle,\
  145.         NULL /****** WRONG ******/,    /* draw_thin_line */\
  146.         pclxl_begin_image,\
  147.         pclxl_image_data,\
  148.         pclxl_end_image,\
  149.         NULL,            /* strip_tile_rectangle */\
  150.         pclxl_strip_copy_rop\
  151.     }
  152.  
  153. gx_device_pclxl far_data gs_pxlmono_device = {
  154.   pclxl_device_body("pxlmono", 8),
  155.   pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
  156. };
  157.  
  158. gx_device_pclxl far_data gs_pxlcolor_device = {
  159.   pclxl_device_body("pxlcolor", 24),
  160.   pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
  161. };
  162.  
  163. /* ---------------- Output utilities ---------------- */
  164.  
  165. /* Write a sequence of bytes. */
  166. #define put_lit(s, bytes) put_bytes(s, bytes, sizeof(bytes))
  167. private void
  168. put_bytes(stream *s, const byte *data, uint count)
  169. {    uint used;
  170.  
  171.     sputs(s, data, count, &used);
  172. }
  173.  
  174. /* Utilities for writing data values. */
  175. /* H-P printers only support little-endian data, so that's what we emit. */
  176. #define da(a) pxt_attr_ubyte, (a)
  177. private void
  178. put_a(stream *s, px_attribute_t a)
  179. {    sputc(s, pxt_attr_ubyte);
  180.     sputc(s, a);
  181. }
  182. #define dub(b) pxt_ubyte, (byte)(b)
  183. private void
  184. put_ub(stream *s, byte b)
  185. {    sputc(s, pxt_ubyte);
  186.     sputc(s, b);
  187. }
  188. #define put_uba(s, b, a)\
  189.     (put_ub(s, b), put_a(s, a))
  190. #define ds(i) (byte)(i), (byte)((i) >> 8)
  191. private void
  192. put_s(stream *s, uint i)
  193. {    sputc(s, (byte)i);
  194.     sputc(s, (byte)(i >> 8));
  195. }
  196. #define dus(i) pxt_uint16, ds(i)
  197. private void
  198. put_us(stream *s, uint i)
  199. {    sputc(s, pxt_uint16);
  200.     put_s(s, i);
  201. }
  202. #define put_usa(s, i, a)\
  203.     (put_us(s, i), put_a(s, a))
  204. private void
  205. put_u(stream *s, uint i)
  206. {    if ( i <= 255 )
  207.       put_ub(s, i);
  208.     else
  209.       put_us(s, i);
  210. }
  211. #define dusp(ix,iy) pxt_uint16_xy, ds(ix), ds(iy)
  212. private void
  213. put_usp(stream *s, uint ix, uint iy)
  214. {    sputc(s, pxt_uint16_xy);
  215.     put_s(s, ix);
  216.     put_s(s, iy);
  217. }
  218. private void
  219. put_usq_fixed(stream *s, fixed x0, fixed y0, fixed x1, fixed y1)
  220. {    sputc(s, pxt_uint16_box);
  221.     put_s(s, fixed2int(x0));
  222.     put_s(s, fixed2int(y0));
  223.     put_s(s, fixed2int(x1));
  224.     put_s(s, fixed2int(y1));
  225. }
  226. #define dss(i) pxt_sint16, ds(i)
  227. private void
  228. put_ss(stream *s, int i)
  229. {    sputc(s, pxt_sint16);
  230.     put_s(s, (uint)i);
  231. }
  232. #define dssp(ix,iy) pxt_sint16_xy, ds(ix), ds(iy)
  233. private void
  234. put_ssp(stream *s, int ix, int iy)
  235. {    sputc(s, pxt_sint16_xy);
  236.     put_s(s, (uint)ix);
  237.     put_s(s, (uint)iy);
  238. }
  239. #define dl(l) ds(l), ds((l) >> 16)
  240. private void
  241. put_l(stream *s, ulong l)
  242. {    put_s(s, (uint)l);
  243.     put_s(s, (uint)(l >> 16));
  244. }
  245. private void
  246. put_r(stream *s, floatp r)
  247. {    /* Convert to single-precision IEEE float. */
  248.     int exp;
  249.     long mantissa = (long)(frexp(r, &exp) * 0x1000000);
  250.  
  251.     if ( exp < -126 )
  252.       mantissa = 0, exp = 0;    /* unnormalized */
  253.     if ( mantissa < 0 )
  254.       exp += 128, mantissa = -mantissa;
  255.     /* All quantities are little-endian. */
  256.     spputc(s, (byte)mantissa);
  257.     spputc(s, (byte)(mantissa >> 8));
  258.     spputc(s, (byte)(((exp + 127) << 7) + ((mantissa >> 16) & 0x7f)));
  259.     spputc(s, (exp + 127) >> 1);
  260. }
  261. private void
  262. put_rl(stream *s, floatp r)
  263. {    sputc(s, pxt_real32);
  264.     put_r(s, r);
  265. }
  266. private void
  267. put_data_length(stream *s, uint num_bytes)
  268. {    if ( num_bytes > 255 )
  269.       { spputc(s, pxt_dataLength);
  270.         put_l(s, (ulong)num_bytes);
  271.       }
  272.     else
  273.       { spputc(s, pxt_dataLengthByte);
  274.         spputc(s, (byte)num_bytes);
  275.       }
  276. }
  277.  
  278. #define put_ac(s, a, op)\
  279. do { static const byte ac_[] = { da(a), op }; put_lit(s, ac_); } while ( 0 )
  280. #define return_put_ac(s, a, op)\
  281. do { put_ac(s, a, op); return 0; } while ( 0 )
  282.  
  283. /* ---------------- Other utilities ---------------- */
  284.  
  285. #define vxdev ((gx_device_vector *)xdev)
  286.  
  287. /* Initialize for a page. */
  288. private void
  289. pclxl_page_init(gx_device_pclxl *xdev)
  290. {    gdev_vector_init(vxdev);
  291.     xdev->in_page = false;
  292.     xdev->fill_rule = gx_path_type_winding_number;
  293.     xdev->clip_rule = gx_path_type_winding_number;
  294.     xdev->color_space = eNoColorSpace;
  295.     xdev->palette.size = 0;
  296.     xdev->font_set = false;
  297. }
  298.  
  299. /* Test whether a RGB color is actually a gray shade. */
  300. #define rgb_is_gray(ci) ((ci) >> 8 == ((ci) & 0xffff))
  301.  
  302. /* Set the color space and (optionally) palette. */
  303. private void
  304. pclxl_set_color_space(gx_device_pclxl *xdev, pxeColorSpace_t color_space)
  305. {    if ( xdev->color_space != color_space )
  306.       { stream *s = gdev_vector_stream(vxdev);
  307.         put_ub(s, color_space);
  308.         put_ac(s, pxaColorSpace, pxtSetColorSpace);
  309.         xdev->color_space = color_space;
  310.       }
  311. }
  312. private void
  313. pclxl_set_color_palette(gx_device_pclxl *xdev, pxeColorSpace_t color_space,
  314.   const byte *palette, uint palette_size)
  315. {    if ( xdev->color_space != color_space ||
  316.          xdev->palette.size != palette_size ||
  317.          memcmp(xdev->palette.data, palette, palette_size)
  318.        )
  319.       { stream *s = gdev_vector_stream(vxdev);
  320.         static const byte csp_[] = {
  321.           da(pxaColorSpace),
  322.           dub(e8Bit), da(pxaPaletteDepth),
  323.           pxt_ubyte_array
  324.         };
  325.  
  326.         put_ub(s, color_space);
  327.         put_lit(s, csp_);
  328.         put_u(s, palette_size);
  329.         put_bytes(s, palette, palette_size);
  330.         put_ac(s, pxaPaletteData, pxtSetColorSpace);
  331.         xdev->color_space = color_space;
  332.         xdev->palette.size = palette_size;
  333.         memcpy(xdev->palette.data, palette, palette_size);
  334.       }
  335. }
  336.  
  337. /* Set a drawing RGB color. */
  338. private int
  339. pclxl_set_color(gx_device_pclxl *xdev, const gx_drawing_color *pdc,
  340.   px_attribute_t null_source, px_tag_t op)
  341. {    stream *s = gdev_vector_stream(vxdev);
  342.     if ( gx_dc_is_pure(pdc) )
  343.       { gx_color_index color = gx_dc_pure_color(pdc);
  344.         if ( xdev->color_info.num_components == 1 || rgb_is_gray(color) )
  345.           { pclxl_set_color_space(xdev, eGray);
  346.             put_uba(s, (byte)color, pxaGrayLevel);
  347.           }
  348.         else
  349.           { pclxl_set_color_space(xdev, eRGB);
  350.             spputc(s, pxt_ubyte_array);
  351.         put_ub(s, 3);
  352.             spputc(s, (byte)(color >> 16));
  353.             spputc(s, (byte)(color >> 8));
  354.             spputc(s, (byte)color);
  355.         put_a(s, pxaRGBColor);
  356.           }
  357.       }
  358.     else if ( gx_dc_is_null(pdc) )
  359.       put_uba(s, 0, null_source);
  360.     else
  361.       return_error(gs_error_rangecheck);
  362.     spputc(s, op);
  363.     return 0;
  364. }
  365.  
  366. /* Test whether we can handle a given color space in an image. */
  367. private bool
  368. pclxl_can_handle_color_space(const gs_color_space *pcs)
  369. {    gs_color_space_index index = gs_color_space_get_index(pcs);
  370.     if ( index == gs_color_space_index_Indexed )
  371.       { if ( pcs->params.indexed.use_proc )
  372.           return false;
  373.         index =
  374.           gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
  375.       }
  376.     return !(index == gs_color_space_index_Separation ||
  377.          index == gs_color_space_index_Pattern);
  378. }
  379.  
  380. /* Set brush, pen, and mode for painting a path. */
  381. private void
  382. pclxl_set_paints(gx_device_pclxl *xdev, gx_path_type_t type)
  383. {    stream *s = gdev_vector_stream(vxdev);
  384.     gx_path_type_t rule = type & gx_path_type_rule;
  385.  
  386.     if ( !(type & gx_path_type_fill) &&
  387.          !gx_dc_is_null(&xdev->fill_color)
  388.        )
  389.       { static const byte nac_[] = {
  390.           dub(0), da(pxaNullBrush), pxtSetBrushSource
  391.         };
  392.         put_lit(s, nac_);
  393.         color_set_null(&xdev->fill_color);
  394.         if ( rule != xdev->fill_rule )
  395.           { put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
  396.                eNonZeroWinding));
  397.             put_ac(s, pxaFillMode, pxtSetFillMode);
  398.         xdev->fill_rule = rule;
  399.           }
  400.       }
  401.     if ( !(type & gx_path_type_stroke) &&
  402.          !gx_dc_is_null(&xdev->stroke_color)
  403.        )
  404.       { static const byte nac_[] = {
  405.           dub(0), da(pxaNullPen), pxtSetPenSource
  406.         };
  407.         put_lit(s, nac_);
  408.         color_set_null(&xdev->stroke_color);
  409.       }
  410. }
  411.  
  412. /* Set the cursor. */
  413. private int
  414. pclxl_set_cursor(gx_device_pclxl *xdev, int x, int y)
  415. {    stream *s = gdev_vector_stream(vxdev);
  416.     put_ssp(s, x, y);
  417.     return_put_ac(s, pxaPoint, pxtSetCursor);
  418. }
  419.  
  420. /* ------ Paths ------ */
  421.  
  422. /* Flush any buffered path points. */
  423. private void
  424. put_np(stream *s, int count, pxeDataType_t dtype)
  425. {    put_uba(s, count, pxaNumberOfPoints);
  426.     put_uba(s, dtype, pxaPointType);
  427. }
  428. private int
  429. pclxl_flush_points(gx_device_pclxl *xdev)
  430. {    int count = xdev->points.count;
  431.  
  432.     if ( count )
  433.       { stream *s = gdev_vector_stream(vxdev);
  434.         px_tag_t op;
  435.         int x = xdev->points.current.x, y = xdev->points.current.y;
  436.         int uor = 0, sor = 0;
  437.         pxeDataType_t data_type;
  438.         int i, di;
  439.         byte diffs[num_points * 2];
  440.  
  441.         /*
  442.          * Writing N lines using a point list requires 11 + 4*N or 11 +
  443.          * 2*N bytes, as opposed to 8*N bytes using separate commands;
  444.          * writing N curves requires 11 + 12*N or 11 + 6*N bytes
  445.          * vs. 22*N.  So it's always shorter to write curves with a
  446.          * list (except for N = 1 with full-size coordinates, but since
  447.          * the difference is only 1 byte, we don't bother to ever use
  448.          * the non-list form), but lines are shorter only if N >= 3
  449.          * (again, with a 1-byte difference if N = 2 and byte
  450.          * coordinates).
  451.          */
  452.         switch ( xdev->points.type )
  453.           {
  454.           case points_none:
  455.         return 0;
  456.           case points_lines:
  457.         op = pxtLinePath;
  458.         if ( count < 3 )
  459.           { for ( i = 0; i < count; ++i )
  460.               { put_ssp(s, xdev->points.data[i].x,
  461.                 xdev->points.data[i].y);
  462.                 put_a(s, pxaEndPoint);
  463.             spputc(s, op);
  464.               }
  465.             goto zap;
  466.           }
  467.         /* See if we can use byte values. */
  468.         for ( i = di = 0; i < count; ++i, di += 2 )
  469.           { int dx = xdev->points.data[i].x - x;
  470.             int dy = xdev->points.data[i].y - y;
  471.  
  472.             diffs[di] = (byte)dx;
  473.             diffs[di + 1] = (byte)dy;
  474.             uor |= dx | dy;
  475.             sor |= (dx + 0x80) | (dy + 0x80);
  476.             x += dx, y += dy;
  477.           }
  478.         if ( !(uor & ~0xff) )
  479.           data_type = eUByte;
  480.         else if ( !(sor & ~0xff) )
  481.           data_type = eSByte;
  482.         else
  483.           break;
  484.         op = pxtLineRelPath;
  485.         /* Use byte values. */
  486. useb:        put_np(s, count, data_type);
  487.         spputc(s, op);
  488.         put_data_length(s, count * 2);  /* 2 bytes per point */
  489.         put_bytes(s, diffs, count * 2);
  490.         goto zap;
  491.           case points_curves:
  492.         op = pxtBezierPath;
  493.         /* See if we can use byte values. */
  494.         for ( i = di = 0; i < count; i += 3, di += 6 )
  495.           { int dx1 = xdev->points.data[i].x - x;
  496.             int dy1 = xdev->points.data[i].y - y;
  497.             int dx2 = xdev->points.data[i + 1].x - x;
  498.             int dy2 = xdev->points.data[i + 1].y - y;
  499.             int dx = xdev->points.data[i + 2].x - x;
  500.             int dy = xdev->points.data[i + 2].y - y;
  501.  
  502.             diffs[di] = (byte)dx1;
  503.             diffs[di + 1] = (byte)dy1;
  504.             diffs[di + 2] = (byte)dx2;
  505.             diffs[di + 3] = (byte)dy2;
  506.             diffs[di + 4] = (byte)dx;
  507.             diffs[di + 5] = (byte)dy;
  508.             uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
  509.             sor |= (dx1 + 0x80) | (dy1 + 0x80) |
  510.               (dx2 + 0x80) | (dy2 + 0x80) |
  511.               (dx + 0x80) | (dy + 0x80);
  512.             x += dx, y += dy;
  513.           }
  514.         if ( !(uor & ~0xff) )
  515.           data_type = eUByte;
  516.         else if ( !(sor & ~0xff) )
  517.           data_type = eSByte;
  518.         else
  519.           break;
  520.         op = pxtBezierRelPath;
  521.         goto useb;
  522.           default:        /* can't happen */
  523.         return_error(gs_error_unknownerror);
  524.           }
  525.         put_np(s, count, eSInt16);
  526.         spputc(s, op);
  527.         put_data_length(s, count * 4);  /* 2 UInt16s per point */
  528.         for ( i = 0; i < count; ++i )
  529.           { put_s(s, xdev->points.data[i].x);
  530.             put_s(s, xdev->points.data[i].y);
  531.           }
  532. zap:        xdev->points.type = points_none;
  533.         xdev->points.count = 0;
  534.       }
  535.     return 0;
  536. }
  537.  
  538. /* ------ Images ------ */
  539.  
  540. /* Begin an image. */
  541. private void
  542. pclxl_write_begin_image(gx_device_pclxl *xdev, uint width, uint height,
  543.   uint dest_width, uint dest_height)
  544. {    stream *s = gdev_vector_stream(vxdev);
  545.  
  546.     put_usa(s, width, pxaSourceWidth);
  547.     put_usa(s, height, pxaSourceHeight);
  548.     put_usp(s, dest_width, dest_height);
  549.     put_ac(s, pxaDestinationSize, pxtBeginImage);
  550. }
  551.  
  552. /* Write rows of an image. */
  553. /****** IGNORES data_bit ******/
  554. private void
  555. pclxl_write_image_data(gx_device_pclxl *xdev, const byte *data, int data_bit,
  556.   uint raster, uint width_bits, int y, int height)
  557. {    stream *s = gdev_vector_stream(vxdev);
  558.     uint width_bytes = (width_bits + 7) >> 3;
  559.     bool compress = width_bytes >= 8;
  560.     uint num_bytes = round_up(width_bytes, 4) * height;
  561.     int i;
  562.  
  563.     put_usa(s, y, pxaStartLine);
  564.     put_usa(s, height, pxaBlockHeight);
  565.     if ( compress )
  566.       { stream_RLE_state rlstate;
  567.         stream_cursor_write w;
  568.         stream_cursor_read r;
  569.         /*
  570.          * H-P printers required that all the data for an operator be
  571.          * contained in a single data block.  Thus, we must allocate
  572.          * a temporary buffer for the compressed data.  Currently we
  573.          * don't go to the trouble of breaking the data up into scan
  574.          * lines if we can't allocate a buffer large enough for the
  575.          * entire transfer.
  576.          */
  577.         byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
  578.                        "pclxl_write_image_data");
  579.  
  580.         if ( buf == 0 )
  581.           goto nc;
  582.         s_RLE_set_defaults_inline(&rlstate);
  583.         rlstate.EndOfData = false;
  584.         s_RLE_init_inline(&rlstate);
  585.         w.ptr = buf - 1;
  586.         w.limit = w.ptr + num_bytes;
  587.         /*
  588.          * If we ever overrun the buffer, it means that the compressed
  589.          * data was larger than the uncompressed.  If this happens,
  590.          * write the data uncompressed.
  591.          */
  592.         for ( i = 0; i < height; ++i )
  593.           { r.ptr = data + i * raster - 1;
  594.             r.limit = r.ptr + width_bytes;
  595.         if ( (*s_RLE_template.process)
  596.                ((stream_state *)&rlstate, &r, &w, false) != 0 ||
  597.              r.ptr != r.limit
  598.            )
  599.           goto ncfree;
  600.         r.ptr = (const byte *)"\000\000\000\000\000";
  601.         r.limit = r.ptr + (-width_bytes & 3);
  602.         if ( (*s_RLE_template.process)
  603.                ((stream_state *)&rlstate, &r, &w, false) != 0 ||
  604.              r.ptr != r.limit
  605.            )
  606.           goto ncfree;
  607.           }
  608.         r.ptr = r.limit;
  609.         if ( (*s_RLE_template.process)
  610.          ((stream_state *)&rlstate, &r, &w, true) != 0
  611.            )
  612.           goto ncfree;
  613.         { uint count = w.ptr + 1 - buf;
  614.  
  615.           put_ub(s, eRLECompression);
  616.           put_ac(s, pxaCompressMode, pxtReadImage);
  617.           put_data_length(s, count);
  618.           put_bytes(s, buf, count);
  619.         }
  620.         return;
  621. ncfree:        gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
  622. nc:        ;
  623.       }
  624.     /* Write the data uncompressed. */
  625.     put_ub(s, eNoCompression);
  626.     put_ac(s, pxaCompressMode, pxtReadImage);
  627.     put_data_length(s, num_bytes);
  628.     for ( i = 0; i < height; ++i )
  629.       { put_bytes(s, data + i * raster, width_bytes);
  630.         put_bytes(s, (const byte *)"\000\000\000\000", -width_bytes & 3);
  631.       }
  632. }
  633.  
  634. /* End an image. */
  635. private void
  636. pclxl_write_end_image(gx_device_pclxl *xdev)
  637. {    spputc(xdev->strm, pxtEndImage);
  638. }
  639.  
  640. /* ------ Fonts ------ */
  641.  
  642. /* Write a string (single- or double-byte). */
  643. private void
  644. put_string(stream *s, const byte *data, uint len, bool wide)
  645. {    if ( wide ) {
  646.       spputc(s, pxt_uint16_array);
  647.       put_u(s, len);
  648.       put_bytes(s, data, len * 2);
  649.     } else {
  650.       spputc(s, pxt_ubyte_array);
  651.       put_u(s, len);
  652.       put_bytes(s, data, len);
  653.     }
  654. }
  655.  
  656. /* Write a 16-bit big-endian value. */
  657. private void
  658. put_us_be(stream *s, uint i)
  659. {    spputc(s, (byte)(i >> 8));
  660.     spputc(s, (byte)i);
  661. }
  662.  
  663. /* Define a bitmap font.  The client must call put_string */
  664. /* with the font name immediately before calling this procedure. */
  665. private void
  666. pclxl_define_bitmap_font(gx_device_pclxl *xdev)
  667. {    stream *s = gdev_vector_stream(vxdev);
  668.     static const byte bfh_[] = {
  669.       da(pxaFontName), dub(0), da(pxaFontFormat),
  670.       pxtBeginFontHeader,
  671.       dus(8 + 6 + 4 + 6), da(pxaFontHeaderLength),
  672.       pxtReadFontHeader,
  673.       pxt_dataLengthByte, 8 + 6 + 4 + 6,
  674.       0, 0, 0, 0,
  675.         254, 0, (max_cached_chars + 255) >> 8, 0,
  676.       'B', 'R', 0, 0, 0, 4
  677.     };
  678.     static const byte efh_[] = {
  679.       0xff, 0xff, 0, 0, 0, 0,
  680.       pxtEndFontHeader
  681.     };
  682.  
  683.     put_lit(s, bfh_);
  684.     put_us_be(s, (uint)(xdev->HWResolution[0] + 0.5));
  685.     put_us_be(s, (uint)(xdev->HWResolution[1] + 0.5));
  686.     put_lit(s, efh_);
  687. }
  688.  
  689. /* Set the font.  The client must call put_string */
  690. /* with the font name immediately before calling this procedure. */
  691. private void
  692. pclxl_set_font(gx_device_pclxl *xdev)
  693. {    stream *s = gdev_vector_stream(vxdev);
  694.     static const byte sf_[] = {
  695.       da(pxaFontName), dub(1), da(pxaCharSize), dus(0), da(pxaSymbolSet),
  696.       pxtSetFont
  697.     };
  698.  
  699.     put_lit(s, sf_);
  700. }
  701.  
  702. /* Define a character in a bitmap font.  The client must call put_string */
  703. /* with the font name immediately before calling this procedure. */
  704. private void
  705. pclxl_define_bitmap_char(gx_device_pclxl *xdev, uint ccode,
  706.   const byte *data, uint raster, uint width_bits, uint height)
  707. {    stream *s = gdev_vector_stream(vxdev);
  708.     uint width_bytes = (width_bits + 7) >> 3;
  709.     uint size = 10 + width_bytes * height;
  710.     uint i;
  711.  
  712.     put_ac(s, pxaFontName, pxtBeginChar);
  713.     put_u(s, ccode);
  714.     put_a(s, pxaCharCode);
  715.     if ( size > 0xffff ) {
  716.       spputc(s, pxt_uint32);
  717.       put_l(s, (ulong)size);
  718.     } else
  719.       put_us(s, size);
  720.     put_ac(s, pxaCharDataSize, pxtReadChar);
  721.     put_data_length(s, size);
  722.     put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
  723.     put_us_be(s, width_bits);
  724.     put_us_be(s, height);
  725.     for ( i = 0; i < height; ++i )
  726.       put_bytes(s, data + i * raster, width_bytes);
  727.     spputc(s, pxtEndChar);
  728. }
  729.  
  730. /* Write the name of the only font we define. */
  731. private void
  732. pclxl_write_font_name(gx_device_pclxl *xdev)
  733. {    stream *s = gdev_vector_stream(vxdev);
  734.  
  735.     put_string(s, (const byte *)"@", 1, false);
  736. }
  737.  
  738. /* Look up a bitmap id, return the index in the character table. */
  739. /* If the id is missing, return an index for inserting. */
  740. private int
  741. pclxl_char_index(gx_device_pclxl *xdev, gs_id id)
  742. {    int i, i_empty = -1;
  743.     uint ccode;
  744.  
  745.     for ( i = (id * char_hash_factor) % countof(xdev->chars.table); ;
  746.           i = (i == 0 ? countof(xdev->chars.table) : i) - 1
  747.         ) {
  748.       ccode = xdev->chars.table[i];
  749.       if ( ccode == 0 )
  750.         return (i_empty >= 0 ? i_empty : i);
  751.       else if ( ccode == 1 ) {
  752.         if ( i_empty < 0 )
  753.           i_empty = i;
  754.         else if ( i == i_empty ) /* full table */
  755.           return i;
  756.       }
  757.       else if ( xdev->chars.data[ccode].id == id )
  758.         return i;
  759.     }
  760. }
  761.  
  762. /* Remove the character table entry at a given index. */
  763. private void
  764. pclxl_remove_char(gx_device_pclxl *xdev, int index)
  765. {    uint ccode = xdev->chars.table[index];
  766.     int i;
  767.  
  768.     if ( ccode < 2 )
  769.       return;
  770.     xdev->chars.count--;
  771.     xdev->chars.used -= xdev->chars.data[ccode].size;
  772.     xdev->chars.table[index] = 1;    /* mark as deleted */
  773.     i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
  774.     if ( xdev->chars.table[i] == 0 ) {
  775.       /* The next slot in probe order is empty. */
  776.       /* Mark this slot and any deleted predecessors as empty. */
  777.       for ( i = index; xdev->chars.table[i] == 1;
  778.         i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
  779.           )
  780.         xdev->chars.table[i] = 0;
  781.     }
  782. }
  783.  
  784. /* Write a bitmap as a text character if possible. */
  785. /* The caller must set the color, cursor, and RasterOp. */
  786. /* We know id != gs_no_id. */
  787. private int
  788. pclxl_copy_text_char(gx_device_pclxl *xdev, const byte *data,
  789.   int raster, gx_bitmap_id id, int w, int h)
  790. {    uint width_bytes = (w + 7) >> 3;
  791.     uint size = width_bytes * h;
  792.     int index;
  793.     uint ccode;
  794.     stream *s = gdev_vector_stream(vxdev);
  795.  
  796.     if ( size > max_char_size )
  797.       return -1;
  798.     index = pclxl_char_index(xdev, id);
  799.     if ( (ccode = xdev->chars.table[index]) < 2 ) {
  800.       /* Enter the character in the table. */
  801.       while ( xdev->chars.used + size > max_char_data ||
  802.           xdev->chars.count >= max_cached_chars - 2
  803.         ) {
  804.         ccode = xdev->chars.next_out;
  805.         index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
  806.         pclxl_remove_char(xdev, index);
  807.         xdev->chars.next_out =
  808.           (ccode == max_cached_chars - 1 ? 2 : ccode + 1);
  809.       }
  810.       index = pclxl_char_index(xdev, id);
  811.       ccode = xdev->chars.next_in;
  812.       xdev->chars.data[ccode].id = id;
  813.       xdev->chars.data[ccode].size = size;
  814.       xdev->chars.table[index] = ccode;
  815.       xdev->chars.next_in =
  816.         (ccode == max_cached_chars - 1 ? 2 : ccode + 1);
  817.       if ( !xdev->chars.count++ ) {
  818.         /* This is the very first character. */
  819.         pclxl_write_font_name(xdev);
  820.         pclxl_define_bitmap_font(xdev);
  821.       }
  822.       if ( !xdev->font_set ) {
  823.         pclxl_write_font_name(xdev);
  824.         pclxl_set_font(xdev);
  825.         xdev->font_set = true;
  826.       }
  827.       xdev->chars.used += size;
  828.       pclxl_write_font_name(xdev);
  829.       pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
  830.     }
  831.     { byte cc_bytes[2];
  832.       cc_bytes[0] = (byte)ccode;
  833.       cc_bytes[1] = ccode >> 8;
  834.       put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
  835.     }
  836.     put_ac(s, pxaTextData, pxtText);
  837.     return 0;
  838. }
  839.  
  840. /* ---------------- Vector implementation procedures ---------------- */
  841.  
  842. #define xvdev ((gx_device_pclxl *)vdev)
  843.  
  844. private int
  845. pclxl_beginpage(gx_device_vector *vdev)
  846. {    /*
  847.      * We can't use gdev_vector_stream here, because this may be called
  848.      * from there before in_page is set.
  849.      */
  850.     stream *s = vdev->strm;
  851.  
  852.     { static const byte page_header_1[] = {
  853.         dub(ePortraitOrientation), da(pxaOrientation),
  854.       };
  855.       put_lit(s, page_header_1);
  856.     }
  857.     {
  858. #define msd(ms, res, w, h)\
  859.   { ms, (w) * 1.0 / (res), (h) * 1.0 / res },
  860.       static const struct {
  861.         pxeMediaSize_t ms;
  862.         float width, height;
  863.       } media_sizes[] = {
  864.         px_enumerate_media(msd)
  865.         { pxeMediaSize_next }
  866.       };
  867.       float w = vdev->width / vdev->HWResolution[0],
  868.         h = vdev->height / vdev->HWResolution[1];
  869.       int i;
  870.       pxeMediaSize_t size;
  871.  
  872.       /* The default is eLetterPaper, media size 0. */
  873.       for ( i = countof(media_sizes) - 2; i > 0; --i )
  874.         if ( fabs(media_sizes[i].width - w) < 5.0/72 &&
  875.          fabs(media_sizes[i].height - h) < 5.0/72
  876.            )
  877.           break;
  878.       size = media_sizes[i].ms;
  879.       /*
  880.        * According to the PCL XL documentation, MediaSize must always
  881.        * be specified, but MediaSource is optional.
  882.        */
  883.       put_uba(s, size, pxaMediaSize);
  884.       if ( size != xvdev->media_size )
  885.         { static const byte page_header_2[] = {
  886.         dub(eAutoSelect), da(pxaMediaSource)
  887.           };
  888.           put_lit(s, page_header_2);
  889.           xvdev->media_size = size;
  890.         }
  891.     }
  892.     spputc(s, pxtBeginPage);
  893.     return 0;
  894. }
  895.  
  896. private int
  897. pclxl_setlinewidth(gx_device_vector *vdev, floatp width)
  898. {    stream *s = gdev_vector_stream(vdev);
  899.     put_us(s, (uint)width);
  900.     return_put_ac(s, pxaPenWidth, pxtSetPenWidth);
  901. }
  902.  
  903. private int
  904. pclxl_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
  905. {    stream *s = gdev_vector_stream(vdev);
  906.     /* The PCL XL cap styles just happen to be identical to PostScript. */
  907.     put_ub(s, (byte)cap);
  908.     return_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
  909. }
  910.  
  911. private int
  912. pclxl_setlinejoin(gx_device_vector *vdev, gs_line_join join)
  913. {    stream *s = gdev_vector_stream(vdev);
  914.     /* The PCL XL join styles just happen to be identical to PostScript. */
  915.     put_ub(s, (byte)join);
  916.     return_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
  917. }
  918.  
  919. private int
  920. pclxl_setmiterlimit(gx_device_vector *vdev, floatp limit)
  921. {    stream *s = gdev_vector_stream(vdev);
  922.     /*
  923.      * Amazingly enough, the PCL XL specification doesn't allow real
  924.      * numbers for the miter limit.
  925.      */
  926.     int i_limit = (int)(limit + 0.5);
  927.  
  928.     put_u(s, max(i_limit, 1));
  929.     return_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
  930. }
  931.  
  932. private int
  933. pclxl_setdash(gx_device_vector *vdev, const float *pattern, uint count,
  934.   floatp offset)
  935. {    stream *s = gdev_vector_stream(vdev);
  936.     if ( count == 0 )
  937.       { static const byte nac_[] = { dub(0), da(pxaSolidLine) };
  938.         put_lit(s, nac_);
  939.       }
  940.     else if ( count > 255 )
  941.       return_error(gs_error_limitcheck);
  942.     else
  943.       { uint i;
  944.         spputc(s, pxt_real32_array);
  945.         put_ub(s, count);
  946.         for ( i = 0; i < count; ++i )
  947.           put_r(s, pattern[i]);
  948.         put_a(s, pxaLineDashStyle);
  949.         if ( offset != 0 )
  950.           { put_rl(s, offset);
  951.             put_a(s, pxaDashOffset);
  952.           }
  953.       }
  954.     spputc(s, pxtSetLineDash);
  955.     return 0;
  956. }
  957.  
  958. private int
  959. pclxl_setlogop(gx_device_vector *vdev, gs_logical_operation_t lop,
  960.   gs_logical_operation_t diff)
  961. {    stream *s = gdev_vector_stream(vdev);
  962.     if ( diff & lop_S_transparent )
  963.       { put_ub(s, (lop & lop_S_transparent ? 1 : 0));
  964.         put_ac(s, pxaTxMode, pxtSetSourceTxMode);
  965.       }
  966.     if ( diff & lop_T_transparent )
  967.       { put_ub(s, (lop & lop_T_transparent ? 1 : 0));
  968.         put_ac(s, pxaTxMode, pxtSetPaintTxMode);
  969.       }
  970.     if ( lop_rop(diff) )
  971.       { put_ub(s, lop_rop(lop));
  972.         put_ac(s, pxaROP3, pxtSetROP);
  973.       }
  974.     return 0;
  975. }
  976.  
  977. private int
  978. pclxl_setfillcolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
  979. {    return pclxl_set_color(xvdev, pdc, pxaNullBrush, pxtSetBrushSource);
  980. }
  981.  
  982. private int
  983. pclxl_setstrokecolor(gx_device_vector *vdev, const gx_drawing_color *pdc)
  984. {    return pclxl_set_color(xvdev, pdc, pxaNullPen, pxtSetPenSource);
  985. }
  986.  
  987. private int
  988. pclxl_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
  989.   fixed y1, gx_path_type_t type)
  990. {    stream *s = gdev_vector_stream(vdev);
  991.     if ( type & (gx_path_type_fill | gx_path_type_stroke) )
  992.       { pclxl_set_paints(xvdev, type);
  993.         put_usq_fixed(s, x0, y0, x1, y1);
  994.         put_ac(s, pxaBoundingBox, pxtRectangle);
  995.       }
  996.     if ( type & gx_path_type_clip )
  997.       { static const byte cr_[] = {
  998.           da(pxaBoundingBox),
  999.           dub(eInterior), da(pxaClipRegion),
  1000.           pxtSetClipRectangle
  1001.         };
  1002.         put_usq_fixed(s, x0, y0, x1, y1);
  1003.         put_lit(s, cr_);
  1004.       }
  1005.     return 0;
  1006. }
  1007.  
  1008. private int
  1009. pclxl_beginpath(gx_device_vector *vdev, gx_path_type_t type)
  1010. {    stream *s = gdev_vector_stream(vdev);
  1011.     spputc(s, pxtNewPath);
  1012.     xvdev->points.type = points_none;
  1013.     xvdev->points.count = 0;
  1014.     return 0;
  1015. }
  1016.  
  1017. private int
  1018. pclxl_moveto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y,
  1019.   bool first)
  1020. {    int code = pclxl_flush_points(xvdev);
  1021.  
  1022.     if ( code < 0 )
  1023.       return code;
  1024.     return pclxl_set_cursor(xvdev,
  1025.                 xvdev->points.current.x = (int)x,
  1026.                 xvdev->points.current.y = (int)y);
  1027. }
  1028.  
  1029. private int
  1030. pclxl_lineto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y)
  1031. {    if ( xvdev->points.type != points_lines ||
  1032.          xvdev->points.count >= num_points
  1033.        )
  1034.       { if ( xvdev->points.type != points_none )
  1035.           { int code = pclxl_flush_points(xvdev);
  1036.         if ( code < 0 )
  1037.           return code;
  1038.           }
  1039.         xvdev->points.current.x = (int)x0;
  1040.         xvdev->points.current.y = (int)y0;
  1041.         xvdev->points.type = points_lines;
  1042.       }
  1043.     { gs_int_point *ppt = &xvdev->points.data[xvdev->points.count++];
  1044.       ppt->x = (int)x, ppt->y = (int)y;
  1045.     }
  1046.     return 0;
  1047. }
  1048.  
  1049. private int
  1050. pclxl_curveto(gx_device_vector *vdev, floatp x0, floatp y0,
  1051.   floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
  1052. {    if ( xvdev->points.type != points_curves ||
  1053.          xvdev->points.count >= num_points - 2
  1054.        )
  1055.       { if ( xvdev->points.type != points_none )
  1056.           { int code = pclxl_flush_points(xvdev);
  1057.         if ( code < 0 )
  1058.           return code;
  1059.           }
  1060.         xvdev->points.current.x = (int)x0;
  1061.         xvdev->points.current.y = (int)y0;
  1062.         xvdev->points.type = points_curves;
  1063.       }
  1064.     { gs_int_point *ppt = &xvdev->points.data[xvdev->points.count];
  1065.       ppt->x = (int)x1, ppt->y = (int)y1, ++ppt;
  1066.       ppt->x = (int)x2, ppt->y = (int)y2, ++ppt;
  1067.       ppt->x = (int)x3, ppt->y = (int)y3;
  1068.     }
  1069.     xvdev->points.count += 3;
  1070.     return 0;
  1071. }
  1072.  
  1073. private int
  1074. pclxl_closepath(gx_device_vector *vdev, floatp x, floatp y,
  1075.   floatp x_start, floatp y_start)
  1076. {    stream *s = gdev_vector_stream(vdev);
  1077.     int code = pclxl_flush_points(xvdev);
  1078.  
  1079.     if ( code < 0 )
  1080.       return code;
  1081.     spputc(s, pxtCloseSubPath);
  1082.     xvdev->points.current.x = (int)x_start;
  1083.     xvdev->points.current.y = (int)y_start;
  1084.     return 0;
  1085. }
  1086.  
  1087. private int
  1088. pclxl_endpath(gx_device_vector *vdev, gx_path_type_t type)
  1089. {    stream *s = gdev_vector_stream(vdev);
  1090.     int code = pclxl_flush_points(xvdev);
  1091.     gx_path_type_t rule = type & gx_path_type_rule;
  1092.  
  1093.     if ( code < 0 )
  1094.       return code;
  1095.     if ( type & (gx_path_type_fill | gx_path_type_stroke) )
  1096.       { pclxl_set_paints(xvdev, type);
  1097.         spputc(s, pxtPaintPath);
  1098.       }
  1099.     if ( type & gx_path_type_clip )
  1100.       { static const byte scr_[] = {
  1101.           dub(eInterior), da(pxaClipRegion), pxtSetClipReplace
  1102.         };
  1103.         if ( rule != xvdev->clip_rule )
  1104.           { put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
  1105.                eNonZeroWinding));
  1106.             put_ac(s, pxaClipMode, pxtSetClipMode);
  1107.         xvdev->clip_rule = rule;
  1108.           }
  1109.         put_lit(s, scr_);
  1110.       }
  1111.     return 0;
  1112. }
  1113.  
  1114. /* Vector implementation procedures */
  1115.  
  1116. private const gx_device_vector_procs pclxl_vector_procs = {
  1117.     /* Page management */
  1118.   pclxl_beginpage,
  1119.     /* Imager state */
  1120.   pclxl_setlinewidth,
  1121.   pclxl_setlinecap,
  1122.   pclxl_setlinejoin,
  1123.   pclxl_setmiterlimit,
  1124.   pclxl_setdash,
  1125.   gdev_vector_setflat,
  1126.   pclxl_setlogop,
  1127.     /* Other state */
  1128.   pclxl_setfillcolor,
  1129.   pclxl_setstrokecolor,
  1130.     /* Paths */
  1131.   gdev_vector_dopath,
  1132.   pclxl_dorect,
  1133.   pclxl_beginpath,
  1134.   pclxl_moveto,
  1135.   pclxl_lineto,
  1136.   pclxl_curveto,
  1137.   pclxl_closepath,
  1138.   pclxl_endpath
  1139. };
  1140.  
  1141. /* ---------------- Driver procedures ---------------- */
  1142.  
  1143. #define vdev ((gx_device_vector *)dev)
  1144. #define xdev ((gx_device_pclxl *)dev)
  1145.  
  1146. /* ------ Open/close/page ------ */
  1147.  
  1148. /* Open the device. */
  1149. private int
  1150. pclxl_open_device(gx_device *dev)
  1151. {    int code;
  1152.     static const char *file_header =
  1153.       "\033%-12345X@PJL ENTER LANGUAGE = PCLXL\n\
  1154. ) HP-PCL XL;1;1;Comment Copyright Aladdin Enterprises 1996\000\n";
  1155.     static const byte stream_header[] = {
  1156.       da(pxaUnitsPerMeasure),
  1157.       dub(0), da(pxaMeasure),
  1158.       dub(eBackChAndErrPage), da(pxaErrorReport),
  1159.       pxtBeginSession,
  1160.       dub(0), da(pxaSourceType),
  1161.       dub(eBinaryLowByteFirst), da(pxaDataOrg),
  1162.       pxtOpenDataSource
  1163.     };
  1164.  
  1165.     vdev->v_memory = dev->memory; /****** WRONG ******/
  1166.     vdev->vec_procs = &pclxl_vector_procs;
  1167.     code = gdev_vector_open_file(vdev, 512);
  1168.     if ( code < 0 )
  1169.       return code;
  1170.     pclxl_page_init(xdev);
  1171.     { stream *s = vdev->strm;
  1172.       /* We have to add 2 to the strlen because the next-to-last */
  1173.       /* character is a null. */
  1174.       put_bytes(s, (const byte *)file_header,
  1175.             strlen(file_header) + 2);
  1176.       put_usp(s, (uint)(dev->HWResolution[0] + 0.5),
  1177.           (uint)(dev->HWResolution[1] + 0.5));
  1178.       put_lit(s, stream_header);
  1179.     }
  1180.     xdev->media_size = pxeMediaSize_next; /* no size selected */
  1181.     memset(&xdev->chars, 0, sizeof(xdev->chars));
  1182.     xdev->chars.next_in = xdev->chars.next_out = 2;
  1183.     return 0;
  1184. }
  1185.  
  1186. /* Wrap up ("output") a page. */
  1187. /* We only support flush = true, and we don't support num_copies != 1. */
  1188. private int
  1189. pclxl_output_page(gx_device *dev, int num_copies, int flush)
  1190. {    if ( xdev->in_page )
  1191.       { stream *s = vdev->strm;
  1192.         spputc(s, pxtEndPage);
  1193.         sflush(s);
  1194.         pclxl_page_init(xdev);
  1195.       }
  1196.     return 0;
  1197. }
  1198.  
  1199. /* Close the device. */
  1200. /* Note that if this is being called as a result of finalization, */
  1201. /* the stream may no longer exist. */
  1202. private int
  1203. pclxl_close_device(gx_device *dev)
  1204. {    FILE *file = vdev->file;
  1205.  
  1206.     if ( xdev->in_page )
  1207.       fputc(pxtEndPage, file);
  1208.     { static const byte file_trailer[] = {
  1209.         pxtCloseDataSource,
  1210.         pxtEndSession,
  1211.         033, '%', '-', '1', '2', '3', '4', '5', 'X'
  1212.       };
  1213.  
  1214.       /* The stream may no longer exist: see above. */
  1215.       fwrite(file_trailer, 1, sizeof(file_trailer), file);
  1216.     }
  1217.     gdev_vector_close_file(vdev);
  1218.     return 0;
  1219. }
  1220.  
  1221. /* ------ One-for-one images ------ */
  1222.  
  1223. private const byte eBit_values[] = {
  1224.   0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
  1225. };
  1226.  
  1227. /* Copy a monochrome bitmap. */
  1228. private int
  1229. pclxl_copy_mono(gx_device *dev, const byte *data,
  1230.   int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
  1231.   gx_color_index zero, gx_color_index one)
  1232. {    int code;
  1233.     stream *s;
  1234.     gx_color_index color0 = zero, color1 = one;
  1235.     gs_logical_operation_t lop;
  1236.     byte palette[2 * 3];
  1237.     int palette_size;
  1238.     pxeColorSpace_t color_space;
  1239.  
  1240.     fit_copy(dev, data, data_x, raster, id, x, y, w, h);
  1241.     code = gdev_vector_update_clip_path(vdev, NULL);
  1242.     if ( code < 0 )
  1243.       return code;
  1244.     pclxl_set_cursor(xdev, x, y);
  1245.     if ( id != gs_no_id && zero == gx_no_color_index &&
  1246.          one != gx_no_color_index && data_x == 0
  1247.        ) {
  1248.       gx_drawing_color dcolor;
  1249.  
  1250.       color_set_pure(&dcolor, one);
  1251.       pclxl_setfillcolor(vxdev, &dcolor);
  1252.       if ( pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0 )
  1253.         return 0;
  1254.     }
  1255.     /*
  1256.      * The following doesn't work if we're writing white with a mask.
  1257.      * We'll fix it eventually.
  1258.      */
  1259.     if ( zero == gx_no_color_index )
  1260.       { if ( one == gx_no_color_index )
  1261.           return 0;
  1262.         lop = rop3_S | lop_S_transparent;
  1263.         color0 = (1 << dev->color_info.depth) - 1;
  1264.       }
  1265.     else if ( one == gx_no_color_index )
  1266.       { lop = rop3_S | lop_S_transparent;
  1267.         color1 = (1 << dev->color_info.depth) - 1;
  1268.       }
  1269.     else
  1270.       { lop = rop3_S;
  1271.       }
  1272.     if ( dev->color_info.num_components == 1 ||
  1273.          (rgb_is_gray(color0) && rgb_is_gray(color1))
  1274.        )
  1275.       { palette[0] = (byte)color0;
  1276.         palette[1] = (byte)color1;
  1277.         palette_size = 2;
  1278.         color_space = eGray;
  1279.       }
  1280.     else
  1281.       { palette[0] = (byte)(color0 >> 16);
  1282.         palette[1] = (byte)(color0 >> 8);
  1283.         palette[2] = (byte)color0;
  1284.         palette[3] = (byte)(color1 >> 16);
  1285.         palette[4] = (byte)(color1 >> 8);
  1286.         palette[5] = (byte)color1;
  1287.         palette_size = 6;
  1288.         color_space = eRGB;
  1289.       }
  1290.     code = gdev_vector_update_log_op(vdev, lop);
  1291.     if ( code < 0 )
  1292.       return 0;
  1293.     pclxl_set_color_palette(xdev, color_space, palette, palette_size);
  1294.     s = gdev_vector_stream(vxdev);
  1295.     { static const byte mi_[] = {
  1296.         dub(e1Bit), da(pxaColorDepth),
  1297.         dub(eIndexedPixel), da(pxaColorMapping)
  1298.       };
  1299.       put_lit(s, mi_);
  1300.     }
  1301.     pclxl_write_begin_image(xdev, w, h, w, h);
  1302.     pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
  1303.     pclxl_write_end_image(xdev);
  1304.     return 0;
  1305. }
  1306.  
  1307. /* Copy a color bitmap. */
  1308. private int
  1309. pclxl_copy_color(gx_device *dev,
  1310.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  1311.   int x, int y, int w, int h)
  1312. {    stream *s;
  1313.     uint source_bit;
  1314.     int code;
  1315.  
  1316.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  1317.     code = gdev_vector_update_clip_path(vdev, NULL);
  1318.     if ( code < 0 )
  1319.       return code;
  1320.     source_bit = sourcex * dev->color_info.depth;
  1321.     if ( (source_bit & 7) != 0 )
  1322.       return gx_default_copy_color(dev, base, sourcex, raster, id,
  1323.                        x, y, w, h);
  1324.     gdev_vector_update_log_op(vdev, rop3_S);
  1325.     pclxl_set_cursor(xdev, x, y);
  1326.     s = gdev_vector_stream(vxdev);
  1327.     { static const byte ci_[] = {
  1328.         da(pxaColorDepth),
  1329.         dub(eDirectPixel), da(pxaColorMapping)
  1330.       };
  1331.       put_ub(s, eBit_values[dev->color_info.depth / dev->color_info.num_components]);
  1332.       put_lit(s, ci_);
  1333.     }
  1334.     pclxl_write_begin_image(xdev, w, h, w, h);
  1335.     pclxl_write_image_data(xdev, base, source_bit, raster,
  1336.                    w * dev->color_info.depth, 0, h);
  1337.     pclxl_write_end_image(xdev);
  1338.     return 0;
  1339. }
  1340.  
  1341. /* Fill a mask. */
  1342. private int
  1343. pclxl_fill_mask(gx_device *dev,
  1344.   const byte *data, int data_x, int raster, gx_bitmap_id id,
  1345.   int x, int y, int w, int h,
  1346.   const gx_drawing_color *pdcolor, int depth,
  1347.   gs_logical_operation_t lop, const gx_clip_path *pcpath)
  1348. {    int code;
  1349.     stream *s;
  1350.  
  1351.     fit_copy(dev, data, data_x, raster, id, x, y, w, h);
  1352.     if ( (data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1 )
  1353.       return gx_default_fill_mask(dev, data, data_x, raster, id,
  1354.                       x, y, w, h, pdcolor, depth,
  1355.                       lop, pcpath);
  1356.     code = gdev_vector_update_clip_path(vdev, pcpath);
  1357.     if ( code < 0 )
  1358.       return code;
  1359.     code = gdev_vector_update_fill_color(vdev, pdcolor);
  1360.     if ( code < 0 )
  1361.       return 0;
  1362.     pclxl_set_cursor(xdev, x, y);
  1363.     if ( id != gs_no_id && data_x == 0 ) {
  1364.       code = gdev_vector_update_log_op(vdev, lop);
  1365.       if ( code < 0 )
  1366.         return 0;
  1367.       if ( pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0 )
  1368.         return 0;
  1369.     }
  1370.     code = gdev_vector_update_log_op(vdev,
  1371.                      lop | rop3_S | lop_S_transparent);
  1372.     if ( code < 0 )
  1373.       return 0;
  1374.     pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
  1375.     s = gdev_vector_stream(vxdev);
  1376.     { static const byte mi_[] = {
  1377.         dub(e1Bit), da(pxaColorDepth),
  1378.         dub(eIndexedPixel), da(pxaColorMapping)
  1379.       };
  1380.       put_lit(s, mi_);
  1381.     }
  1382.     pclxl_write_begin_image(xdev, w, h, w, h);
  1383.     pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
  1384.     pclxl_write_end_image(xdev);
  1385.     return 0;
  1386. }
  1387.  
  1388. /* Do a RasterOp. */
  1389. private int
  1390. pclxl_strip_copy_rop(gx_device *dev,
  1391.   const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
  1392.   const gx_color_index *scolors,
  1393.   const gx_strip_bitmap *textures, const gx_color_index *tcolors,
  1394.   int x, int y, int width, int height,
  1395.   int phase_x, int phase_y, gs_logical_operation_t lop)
  1396. {    /* We can't do general RasterOps yet. */
  1397.     /****** WORK IN PROGRESS ******/
  1398.     return 0;
  1399. }
  1400.  
  1401. /* ------ High-level images ------ */
  1402.  
  1403. typedef struct pclxl_image_enum_s {
  1404.   gs_memory_t *memory;
  1405.   void *default_info;
  1406.   uint bits_per_row;
  1407.   int bits_per_pixel;
  1408.   int y, h;
  1409. } pclxl_image_enum_t;
  1410. gs_private_st_ptrs1(st_pclxl_image_enum, pclxl_image_enum_t,
  1411.   "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
  1412.   pclxl_image_enum_reloc_ptrs, default_info);
  1413.  
  1414. /* Start processing an image. */
  1415. private int
  1416. pclxl_begin_image(gx_device *dev,
  1417.   const gs_imager_state *pis, const gs_image_t *pim,
  1418.   gs_image_format_t format, const gs_int_rect *prect,
  1419.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
  1420.   gs_memory_t *mem, void **pinfo)
  1421. {    const gs_color_space *pcs = pim->ColorSpace;
  1422.     pclxl_image_enum_t *pie;
  1423.     gs_matrix mat;
  1424.     int num_components;
  1425.     int bits_per_pixel;
  1426.  
  1427.     pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
  1428.                   "pclxl_begin_image");
  1429.     if ( pie == 0 )
  1430.       return_error(gs_error_VMerror);
  1431.     pie->memory = mem;
  1432.     *pinfo = pie;
  1433.     if ( pim->ImageMask )
  1434.       bits_per_pixel = num_components = 1;
  1435.     else
  1436.       num_components = gs_color_space_num_components(pcs),
  1437.         bits_per_pixel = pim->BitsPerComponent * num_components;
  1438.     gs_matrix_invert(&pim->ImageMatrix, &mat);
  1439.     gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
  1440.     /* Currently we only handle portrait transformations. */
  1441.     if ( mat.xx <= 0 || mat.xy != 0 || mat.yx != 0 || mat.yy <= 0 ||
  1442.          (pim->ImageMask ?
  1443.           (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
  1444.           (!pclxl_can_handle_color_space(pim->ColorSpace) ||
  1445.            (bits_per_pixel != 1 && bits_per_pixel != 4 &&
  1446.         bits_per_pixel != 8))) ||
  1447.          format != gs_image_format_chunky ||
  1448.          prect
  1449.        )
  1450.       { int code = gx_default_begin_image(dev, pis, pim, format, prect,
  1451.                           pdcolor, pcpath, mem,
  1452.                           &pie->default_info);
  1453.         if ( code < 0 )
  1454.           gs_free_object(mem, pie, "pclxl_begin_image");
  1455.         return code;
  1456.       }
  1457.     pie->default_info = 0;
  1458.       { stream *s = gdev_vector_stream(vxdev);
  1459.         gs_logical_operation_t lop = pis->log_op;
  1460.         int code = gdev_vector_update_log_op
  1461.           (vdev, (pim->ImageMask || pim->CombineWithColor ? lop :
  1462.               rop3_know_T_0(lop)));
  1463.         int bpc = pim->BitsPerComponent;
  1464.         int sample_max = (1 << bpc) - 1;
  1465.         byte palette[256 * 3];
  1466.         int i;
  1467.  
  1468.         if ( code < 0 )
  1469.           return code;
  1470.         pie->bits_per_pixel = bits_per_pixel;
  1471.         pie->bits_per_row = bits_per_pixel * pim->Width;
  1472.         pie->y = 0;
  1473.         pie->h = pim->Height;
  1474.         pclxl_set_cursor(xdev, (int)((mat.tx + 0.5) / xdev->scale.x),
  1475.                  (int)((mat.ty + 0.5) / xdev->scale.y));
  1476.         for ( i = 0; i < 1 << bits_per_pixel; ++i )
  1477.           { gs_client_color cc;
  1478.         gx_device_color devc;
  1479.         int cv = i, j;
  1480.  
  1481.         for ( j = num_components - 1; j >= 0; cv >>= bpc, --j )
  1482.           cc.paint.values[j] = pim->Decode[j * 2] +
  1483.             (cv & sample_max) *
  1484.              (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
  1485.               sample_max;
  1486.         (*pcs->type->remap_color)
  1487.           (&cc, pcs, &devc, pis, dev, gs_color_select_source);
  1488.         if ( !gx_dc_is_pure(&devc) )
  1489.           return_error(gs_error_Fatal);
  1490.         if ( dev->color_info.num_components == 1 )
  1491.           palette[i] = (byte)gx_dc_pure_color(&devc);
  1492.         else
  1493.           { gx_color_index ci = gx_dc_pure_color(&devc);
  1494.             byte *ppal = &palette[i * 3];
  1495.             ppal[0] = (byte)(ci >> 16);
  1496.             ppal[1] = (byte)(ci >> 8);
  1497.             ppal[2] = (byte)ci;
  1498.           }
  1499.           }
  1500.         if ( dev->color_info.num_components == 1 )
  1501.           pclxl_set_color_palette(xdev, eGray, palette,
  1502.                       1 << bits_per_pixel);
  1503.         else
  1504.           pclxl_set_color_palette(xdev, eRGB, palette,
  1505.                       3 << bits_per_pixel);
  1506.         { static const byte ii_[] = {
  1507.             da(pxaColorDepth),
  1508.         dub(eIndexedPixel), da(pxaColorMapping)
  1509.           };
  1510.           put_ub(s, eBit_values[bits_per_pixel]);
  1511.           put_lit(s, ii_);
  1512.         }
  1513.         pclxl_write_begin_image(xdev, pim->Width, pim->Height,
  1514.                     (uint)(pim->Width * mat.xx),
  1515.                     (uint)(pim->Height * mat.yy));
  1516.       }
  1517.     return 0;
  1518. }
  1519.  
  1520. /* Process the next piece of an image. */
  1521. private int
  1522. pclxl_image_data(gx_device *dev,
  1523.   void *info, const byte **planes, int data_x, uint raster, int height)
  1524. {    pclxl_image_enum_t *pie = info;
  1525.  
  1526.     if ( pie->default_info )
  1527.       return gx_default_image_data(dev, pie->default_info, planes, data_x,
  1528.                        raster, height);
  1529.     if ( height > pie->h - pie->y )
  1530.       height = pie->h - pie->y;
  1531.     pclxl_write_image_data(xdev, planes[0], data_x * pie->bits_per_pixel,
  1532.                    raster, pie->bits_per_row, pie->y, height);
  1533.     return (pie->y += height) >= pie->h;
  1534. }
  1535.  
  1536. /* Clean up by releasing the buffers. */
  1537. private int
  1538. pclxl_end_image(gx_device *dev, void *info, bool draw_last)
  1539. {    pclxl_image_enum_t *pie = info;
  1540.     int code = 0;
  1541.  
  1542.     if ( pie->default_info )
  1543.       code = gx_default_end_image(dev, pie->default_info, draw_last);
  1544.     else
  1545.       { /* Fill out to the full image height. */
  1546.         /****** WRONG -- REST OF IMAGE SHOULD BE TRANSPARENT ******/
  1547.         if ( pie->h > pie->y )
  1548.           { uint bytes_per_row =  (pie->bits_per_row + 7) >> 3;
  1549.             byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
  1550.                        "pclxl_end_image(fill)");
  1551.  
  1552.         if ( row == 0 )
  1553.           return_error(gs_error_VMerror);
  1554.         memset(row, 0, bytes_per_row);
  1555.         for ( ; pie->y < pie->h; pie->y++ )
  1556.           pclxl_write_image_data(xdev, row, 0, bytes_per_row,
  1557.                      pie->bits_per_row, pie->y, 1);
  1558.         gs_free_object(pie->memory, row, "pclxl_end_image(fill)");
  1559.           }
  1560.         pclxl_write_end_image(xdev);
  1561.       }
  1562.     gs_free_object(pie->memory, pie, "pclxl_end_image");
  1563.     return code;
  1564. }
  1565.  
  1566. #undef vdev
  1567.